package com.cmc.cloud.cmclink.doc.controller.admin.si;

import com.cmc.cloud.cmclink.doc.api.document.emums.DoOperationTypeEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.ExImTypeEnum;
import com.cmc.cloud.cmclink.doc.constants.UrlConstants;
import com.cmc.cloud.cmclink.doc.service.si.*;
import com.cmc.cloud.cmclink.doc.util.CostChargeWithBlnoUtil;
import com.cmc.cloud.cmclink.doc.vo.blnochargevo.BlnoCheckMsgReqVO;
import com.cmc.cloud.cmclink.doc.service.si.BlnoArrivalNoticeService;
import com.cmc.cloud.cmclink.doc.service.si.BlnoService;
import com.cmc.cloud.cmclink.doc.vo.blnovo.*;
import com.cmc.cloud.cmclink.doc.vo.blnovo.arrivalnoticevo.DownloadAndSendEmailVO;
import com.cmc.cloud.cmclink.doc.vo.blnovo.operatevo.*;
import com.cmes.framework.biz.advice.annotations.UseResponsePropertyAdvice;
import com.cmes.framework.common.pojo.CommonResult;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.excel.core.util.ExcelUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

import static com.cmc.cloud.cmclink.doc.service.impl.si.BlnoServiceImpl.AN;


/**
 * 提单主信息进口前端接口Controller
 *
 * @author 申天青
 */
@Tag(name = "管理后台 - 提单主信息进口")
@RestController
@Validated
@RequestMapping(UrlConstants.APPLICATION_URL + "/blno"+"/import")
public class BlnoImController {

    @Resource
    private BlnoService blnoService;

    @Resource
    private BlnoArrivalNoticeService blnoArrivalNoticeService;

    @Resource
    private CostChargeWithBlnoUtil costChargeWithBlnoUtil;
    @Resource
    private BlnoLocalCostImService blnoLocalCostImService;
    @Resource
    private BlnoFreightService blnoFreightService;
    @Resource
    private BlnoLocalChargeService blnoLocalChargeService;


    @Operation(summary = "获得提单主信息分页")
    @PostMapping("/page")
    @UseResponsePropertyAdvice
    @PreAuthorize("@ss.hasPermission({'doc:maintainBLIM:page'})")
    public CommonResult<PageResult<BlnoImPageRespVO>> getBlnoPage(@Valid @RequestBody BlnoImPageReqVO pageVO) {
        PageResult<BlnoImPageRespVO> blnoPage = blnoService.getBlnoImPage(pageVO);
        return CommonResult.success(blnoPage);
    }
    @Operation(summary = "excel导出 全部导出分页无效")
    @PostMapping("/excel-export")
    @PreAuthorize("@ss.hasPermission('doc:maintainBLIM:export')")
    public void exportExcelTemplate(HttpServletResponse response, @Valid @RequestBody BlnoImPageReqVO pageVO) throws IOException {

        //file name "SI_" +YYYYMMDDHHMMSS 当前时间格式化 SI_202508121647
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String formattedString = now.format(formatter);

        String fileName = formattedString + ".xlsx";

        List<BlnoImPageRespVO> exportList = blnoService.exportBlnoIm(pageVO);
        // FIXME 一定要向response写数据之前设置响应头，否则会出现文件下载失败
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
        ExcelUtils.write(response, fileName, "SI", BlnoImPageRespVO.class, exportList);
    }

    /**
     * 设置 D/O前 调用箱管接口获取收取押金状态及付押金公司名称 如已收提示msg：押金公司名称+ 提单号+ ‘是否继续D/O？’
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "设置 D/O前 调用箱管接口获取收取押金状态及付押金公司名称 如已收提示msg：押金公司名称+ 提单号+ ‘是否继续D/O？’")
    @PostMapping("/getDOCheckDepositStatus")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:getDOCheckDepositStatus')")
    public CommonResult<BlnoOperateCheckDepositStatusRespVO> getDoCheckDepositStatus(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO) {
        BlnoOperateCheckDepositStatusRespVO respVO = new BlnoOperateCheckDepositStatusRespVO();
        respVO.setDepositHasBeenCollectedNameBlnoList(blnoService.getBlContainDepositStatus(blnoOperateReqVO));
        return CommonResult.success(respVO);
    }
    /**
     * 设置 D/O
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "设置 D/O")
    @PostMapping("/setDO")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:setDO')")
    public CommonResult<Void> setDO(@Valid @RequestBody BlnoOperateDoReqVO blnoOperateReqVO) {
        blnoService.setDO(blnoOperateReqVO);
        return CommonResult.success();
    }
    /**
     * sendEdo
     * @param blnoOperateReqVO
     */
    @Operation(summary = "sendEdo")
    @PostMapping("/sendEdo")
    public CommonResult<Void> sendEdo(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO) {
        blnoService.sendEdo(blnoOperateReqVO, DoOperationTypeEnum.SET_DO);
        return CommonResult.success();
    }

    /**
     * 测试edo发送
     *
     * @param blnoOperateReqVO 提单发送EDO操作对象
     * @param doOperation do操作类型
     */
    @Operation(summary = "testSendEdo")
    @PostMapping("/testSendEdo/{doOperation}")
    public CommonResult<Void> testSendEdo(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO ,@PathVariable("doOperation")String doOperation ) {
        blnoService.sendEdo(blnoOperateReqVO, DoOperationTypeEnum.valueOf(doOperation));
        return CommonResult.success();
    }

    /**
     * 取消 D/O
     */
    @Operation(summary = "取消 D/O")
    @PostMapping("/cancelDO")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:cancelDO')")
    public CommonResult<Void> cancelDO(@Valid @RequestBody BlnoOperateCancelDoReqVO blnoOperateReqVO) {
        blnoService.cancelDO(blnoOperateReqVO);
        return CommonResult.success();
    }
//    /**
//     * 清空 telex
//     *
//     * @param blnoOperateReqVO
//     * @return List<BlnoDO>
//     */
//    @Operation(summary = " 清空 telex")
//    @PostMapping("/cancelTelex")
//    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:cancelTelexSeaway')")
//    public CommonResult<Void> cancelTelex(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO) {
//        blnoService.cancelTelex(blnoOperateReqVO);
//        return CommonResult.success();
//    }
    /**
     * noted telex
     *
     * @param blnoOperateReqVO
     * @return List<BlnoDO>
     */
    @Operation(summary = " noted telex")
    @PostMapping("/notedTelex")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:noteTelexSeaway')")
    public CommonResult<Void> notedTelex(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO) {
        blnoService.notedTelex(blnoOperateReqVO);
        return CommonResult.success();
    }

    /**
     * lockDO
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "lockDO")
    @PostMapping("/lockDO")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:lockDO')")
    public CommonResult<Void> lockDO(@Valid @RequestBody BlnoOperateLockDoReqVO blnoOperateReqVO) {
        blnoService.lockDO(blnoOperateReqVO);
        return CommonResult.success();
    }
    /**
     * unLockDO
     */
    @Operation(summary = "unLockDO")
    @PostMapping("/unLockDO")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:unLockDO')")
    public CommonResult<Void> unLockDO(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO) {
        blnoService.unLockDO(blnoOperateReqVO);
        return CommonResult.success();
    }
    /**
     * @param blnoOperateReqVO
     */
    @Operation(summary = "lockCharge前 " +
            "1.检查 费用是否已锁定 如锁定 提示：提单号xxxx 费用已锁定，无需再次锁定！" +
            "2.校验费用是否已计算 如存在未计算费用的提单\n" +
            "     * 做出提示：提单号xxxxxxxx、xxxxxxxx无#应收/应付#费用，是否继续锁定？")
    @PostMapping("/lockChargeCheck")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:lockCharge')")
    public CommonResult<BlnoCheckMsgReqVO> lockChargeCheck(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO) {
        BlnoCheckMsgReqVO checkMsgReqVO = blnoService.lockChargeCheck(blnoOperateReqVO.getBlnoIds());
        return CommonResult.success(checkMsgReqVO);
    }
    /**
     * lockCharge
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "lockCharge")
    @PostMapping("/lockCharge")
    @PreAuthorize("@ss.hasPermission({'doc:operateBLIM:lockCharge','doc:transitProxy:setCargo'})")
    public CommonResult<Void> lockCharge(@Valid @RequestBody BlnoOperateLockChargeReqVO blnoOperateReqVO) {
        blnoService.lockCharge(blnoOperateReqVO);
        List<Long> ids = blnoOperateReqVO.getBlnoIds();
        //锁定后提示“”锁定完成“”并调用接口发送提单未结转的Local Charge 信息到财务
        blnoLocalChargeService.toAccount(ExImTypeEnum.IM.getValue(), ids);
        return CommonResult.success();
    }
    /**
     * setCommodityCn
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "设置中文品名")
    @PostMapping("/setCommodityCn")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:setCommodityCn')")
    public CommonResult<Void> setCommodityCn(@Valid @RequestBody BlnoOperateCommodityCnReqVO blnoOperateReqVO) {
        blnoService.setCommodityCn(blnoOperateReqVO.getBlnoIds(), blnoOperateReqVO.getCommodityCn() );
        return CommonResult.success();
    }
    /**
     * setTransitTerm
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "setTransitTerm")
    @PostMapping("/setTransitTerm")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:setTransitTerm')")
    public CommonResult<Void> setTransitTerm(@Valid @RequestBody BlnoOperateTransitTermReqVO blnoOperateReqVO) {
        blnoService.setTransitTerm(blnoOperateReqVO);
        return CommonResult.success();
    }
    /**
     * setStuffLocation
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "setStuffLocation")
    @PostMapping("/setStuffLocation")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:setStuffLocation')")
    public CommonResult<Void> setStuffLocation(@Valid @RequestBody BlnoOperateStuffLocationReqVO blnoOperateReqVO) {
        blnoService.setStuffLocation(blnoOperateReqVO);
        return CommonResult.success();
    }
    /**
     * setDOPart
     *
     * @param blnoOperateReqVos
     */
    @Operation(summary = "setDOPart")
    @PostMapping("/setDOPart")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:setDOPart')")
    public CommonResult<Void> setDoPart(@Valid @RequestBody List<BlnoOperateDoPartReqVO> blnoOperateReqVos) {
        blnoService.setDoPart(blnoOperateReqVos);
        return CommonResult.success();
    }
    /**
     * printDocument
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "printDocument")
    @PostMapping("/printDocument")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:printDocument')")
    public void printDocument(HttpServletResponse response,@Valid @RequestBody BlnoOperatePrintDocumentReqVO blnoOperateReqVO) throws IOException {
        //ArrivalNotice
        if(blnoOperateReqVO.getDocumentType().equals(AN)){
            String url = "";
            MultipartFile multipartFile = blnoArrivalNoticeService.genArrivalNoticePdfUrl(blnoOperateReqVO.getCurrentPort(), blnoOperateReqVO.getBlnoId(),url);
            if(multipartFile==null){
                return;
            }
            // 设置响应头，支持文件下载
            response.setContentType("application/pdf");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + multipartFile.getOriginalFilename() + "\"");
            response.setHeader("Content-Length", String.valueOf(multipartFile.getSize()));
            response.setHeader("Content-Length", String.valueOf(multipartFile.getSize()));
            response.setHeader("pdfUrl", url);

            // 将文件流写入响应
//            multipartFile.getInputStream().transferTo(response.getOutputStream());
            try (InputStream inputStream = multipartFile.getInputStream();
                 OutputStream outputStream = response.getOutputStream()) {
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                outputStream.flush();
            } catch (IOException e) {
                throw new RuntimeException("文件写入响应失败", e);
            }

            response.flushBuffer();
        } else {
            blnoService.printDocument(response,blnoOperateReqVO);
        }
    }
//    /**
//     * setSendArriveNotice
//     *
//     * @param blnoOperateReqVO
//     */
//    @Operation(summary = "setSendArriveNotice")
//    @PostMapping("/setSendArriveNotice")
//    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:setSendArriveNotice')")
//    public CommonResult<Void> setSendArriveNotice(@Valid @RequestBody BlnoOperateDoReqVO blnoOperateReqVO) {
//        blnoService.setSendArriveNotice(blnoOperateReqVO);
//        return CommonResult.success();
//    }
    /**
     * 从财务获取DOPart
     *
     * @param blnoOperateReqVO
     */
    @Operation(summary = "从财务获取DOPart")
    @PostMapping("/getDOPart")
    @PreAuthorize("@ss.hasPermission('doc:operateBLIM:getDOPart')")
    public CommonResult<List<BlnoDoPartRespVO>> getDoPart(@Valid @RequestBody BlnoOperateIdsReqVO blnoOperateReqVO) {
        return CommonResult.success(blnoService.getDoPart(blnoOperateReqVO.getBlnoIds()));
    }

    /**
     * SendArriveNotice
     *
     * @param reqVO 请求参数
     */
    @Operation(summary = "ARRIVAL NOTICE（到货通知）")
    @PostMapping("/sendArrivalNotice")
    public CommonResult<Void> sendArrivalNotice(@Valid @RequestBody BlnoSendArrivalReqVO reqVO) {
        blnoArrivalNoticeService.sendArrivalNotice(reqVO);
        return CommonResult.success();
    }

    /**
     * SendArriveNotice
     *
     * @param reqList 请求参数
     */
    @Operation(summary = "下载附件并发送邮件")
    @PostMapping("/send/email")
    public CommonResult<Void> downloadAndSendEmail(@Valid @RequestBody List<DownloadAndSendEmailVO> reqList) {
        blnoArrivalNoticeService.downloadAndSendEmail(reqList);
        return CommonResult.success();
    }
}
